/*

    This file is part of Hometree.

    Hometree is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Hometree is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Hometree.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2011,2012 Roman Held

*/
/********************************************************************\
                            Includes
\********************************************************************/
#include <QObject>
#include <QString>
#include "htr/htrclient.h"
#include "htr/htrglobal.h"

/********************************************************************\
                          Konstanten
\********************************************************************/
#define CLIENT_NETWORK_PROTOCOL 1

/********************************************************************\
                          Declaration
\********************************************************************/
/*--------------------------------------------------------------------
*/
HtrClient::HtrClient()
 : QObject()
{
  mState = StOffline;
  mClientNetProtocol = CLIENT_NETWORK_PROTOCOL;
  mServerNetProtocol = 0;

  connect(&mSocket, SIGNAL(hasConnected(bool)),
          this, SLOT(handleState()),Qt::QueuedConnection);
  connect(&mSocket, SIGNAL(error(QAbstractSocket::SocketError)),
          this, SLOT(handleSocketError()));
  connect(&mAutoConnectTimer, SIGNAL(timeout()),
          this, SLOT(reconnect()));

  connect(&mSocket, SIGNAL(readyRead()),
         this, SLOT(handleMsg()));
  connect(&mSocket, SIGNAL(reading()),
         this, SIGNAL(rx()));
  connect(&mSocket, SIGNAL(writing()),
         this, SIGNAL(tx()));

  connect(this, SIGNAL(stateChanged()),
          this, SLOT(handleState()), Qt::QueuedConnection);
}

/*--------------------------------------------------------------------
*/
HtrClient::~HtrClient()
{
}

/*--------------------------------------------------------------------
*/
void  HtrClient::connectToHost(const QString &host, int port)
{
  mNetHost = host;
  mNetPort = port;
  setState(StConnect);
}

/*--------------------------------------------------------------------
*/
void HtrClient::close()
{
  mSocket.close();
}

/*--------------------------------------------------------------------
*/
void  HtrClient::reconnect()
{
  setState(StConnect);
}
    
/*--------------------------------------------------------------------
*/
bool  HtrClient::isReady()
{
  return mState == StConnected;
}

/*--------------------------------------------------------------------
*/
void  HtrClient::setAutoConnect(bool autoCon)
{
  mAutoConnect = autoCon;
}

/*--------------------------------------------------------------------
*/
bool  HtrClient::autoConnect() const
{
  return mAutoConnect;
}

/*--------------------------------------------------------------------
*/
QDataStream &HtrClient::prepareStream(Htr::Net::ClMessageType t)
{
  QDataStream &publicStream = mSocket.prepareStream();
  publicStream << (qint32)t;
  return publicStream;
}

/*--------------------------------------------------------------------
*/
void HtrClient::writeStream()
{
  mSocket.writeStream();
}

/*--------------------------------------------------------------------
*/
void HtrClient::setupStream(QDataStream &s)
{
  mSocket.setupStream(s);
}

/*--------------------------------------------------------------------
*/
void  HtrClient::keepAlive()
{

}

/*--------------------------------------------------------------------
*/
void HtrClient::handleMsg()
{
  mSocket.next();
  QDataStream &inStream = mSocket.readStream();
  qint32 msg;
  inStream >> msg;
  switch (msg) {
    case Htr::Net::ClWelcomeMsg:
      handleWelcomeMsg(inStream); break;
    case Htr::Net::ClIdentMsg: 
      handleIdentMsg(inStream);   break;
    case Htr::Net::ClSmsMsg:
      handleSmsMsg(inStream);     break;
    case Htr::Net::ClResourceMsg: 
      handleResourceMsg(inStream);break;
    case Htr::Net::ClMonitorMsg: 
      handleMonitorMsg(inStream); break;
  }
}

/*--------------------------------------------------------------------
*/
void  HtrClient::handleState()
{
  switch (mState) {
    case StOffline:
      if (mSocket.isConnected())
        mSocket.disconnectFromHost();
      if (mAutoConnect)
        mAutoConnectTimer.start(10000);
      break;
    case StConnect:
      if (mAutoConnectTimer.isActive())
        mAutoConnectTimer.stop();
      if (mSocket.isConnected())
        mSocket.disconnectFromHost();
      mServerNetProtocol =  0;
      mSocket.connectToHost(mNetHost,mNetPort);
      setState(StConnecting);
      break;
    case StConnecting:
      if (mSocket.isConnected())
        setState(StSndWelcome);
      // TODO: Timeout?
      break;
    case StSndWelcome:
      if (!mSocket.isConnected())
        setState(StOffline);
      else {
        sendWelcomeMsg();
        setState(StRcvWelcome);
      } break;
    case StRcvWelcome:
      if (mServerNetProtocol > 0)
        setState(StConnected);
      break;
    case StConnected:
      if (!mSocket.isConnected())
        setState(StOffline);
      break;
  }
}

/*--------------------------------------------------------------------
*/
void  HtrClient::handleSocketError()
{
  setState(StOffline);
}

/*--------------------------------------------------------------------
*/
void  HtrClient::setState(HtrClient::ClientState s)
{
  if (mState == s)
    return;

  mState = s;
  emit stateChanged();
}


/*--------------------------------------------------------------------
*/
void HtrClient::handleIdentMsg(QDataStream &inStream)
{
  QString url;
  qint32  id;
  qint32  type;
  inStream >> url;
  inStream >> id;
  inStream >> type;
  emit urlIdent(url,id,type);
}

/*--------------------------------------------------------------------
*/
void HtrClient::handleWelcomeMsg(QDataStream &inStream)
{
  inStream >> mServerNetProtocol;
  Q_ASSERT(mServerNetProtocol > 0);
  // TODO: if incompatible state = error?
  setState(StConnected);
}

/*--------------------------------------------------------------------
*/
void HtrClient::handleSmsMsg(QDataStream &inStream)
{
  QString sms;
  inStream >> sms;

  emit sysopMsg(sms);
}

/*--------------------------------------------------------------------
*/
void HtrClient::handleResourceMsg(QDataStream &inStream)
{
  qint32  id;
  inStream >> id;
  emit resourceMsg(id,inStream);
}

/*--------------------------------------------------------------------
*/
void HtrClient::handleMonitorMsg(QDataStream &inStream)
{
  emit monitorMsg(inStream);
}

/*--------------------------------------------------------------------
*/
void HtrClient::sendWelcomeMsg()
{
  prepareStream(Htr::Net::ClWelcomeMsg) << mClientNetProtocol;
  writeStream();
}
